﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Util
{
    /// <summary>
    /// Represents a named value. A StatisticsVariable may be used to track data in a fashion that will allow the data to be
    /// viewed or dumped at any time.  Statistics are kept in a pool and are grouped in contexts. Statistics can be dumped
    /// as a whole or by context.
    /// </summary>
    public class StatisticsVariable
    {
        private static Dictionary<String, StatisticsVariable> pool = new Dictionary<String, StatisticsVariable>();

        /** the value of this StatisticsVariable. It can be manipulated directly by the application. */
        public double value;

        private String name;        // the name of this value
        private Boolean enabled;        // if true this var is enabled


        /// <summary>
        /// Gets the StatisticsVariable with the given name from the given context. If the statistic does not currently
        /// exist, it is created. If the context does not currently exist, it is created. 
        /// </summary>
        /// <param name="statName">the name of the StatisticsVariable</param>
        /// <returns>the StatisticsVariable with the given name and context</returns>
        static public StatisticsVariable getStatisticsVariable(String statName) 
        {
            StatisticsVariable stat = null;
            
            if(!pool.ContainsKey(statName))
            {
                if (stat == null) 
                {
                    stat = new StatisticsVariable(statName);
                    pool.Add(statName, stat);
                }
            }
            else
                stat = pool[statName];
            return stat;
        }


        /**
        /// Gets the StatisticsVariable with the given name for the given instance and context. This is a convenience
        /// function.
         *
        /// @param instanceName the instance name of creator
        /// @param statName     the name of the StatisticsVariable
         */
        static public StatisticsVariable getStatisticsVariable(
                String instanceName, String statName) 
        {
            return getStatisticsVariable(instanceName + '.' + statName);
        }


        /** Dump all of the StatisticsVariable in the given context */
        static public void dumpAll() 
        {
            Trace.WriteLine(" ========= statistics  " + "=======");
            foreach (StatisticsVariable stats in pool.Values) 
            {
                stats.dump();
            }
        }


        /** Resets all of the StatisticsVariables in the given context */
        static public void resetAll() 
        {
            foreach (StatisticsVariable stats in pool.Values) 
            {
                stats.reset();
            }
        }


        /**
        /// Contructs a StatisticsVariable with the given name and context
         *
        /// @param statName the name of this StatisticsVariable
         */
        private StatisticsVariable(String statName) 
        {
            this.name = statName;
            this.value = 0.0;
        }


        /**
        /// Retrieves the name of this StatisticsVariable
         *
        /// @return the name of this StatisticsVariable
         */
        public String getName() 
        {
            return name;
        }


        /**
        /// Retrieves the value for this StatisticsVariable
         *
        /// @return the current value for this StatisticsVariable
         */
        public double getValue() 
        {
            return value;
        }


        /**
        /// Sets the value for this StatisticsVariable
         *
        /// @param value the new value
         */
        public void setValue(double value) 
        {
            this.value = value;
        }


        /** Resets this StatisticsVariable. The value is set to zero. */
        public void reset() 
        {
            setValue(0.0);
        }


        /** Dumps this StatisticsVariable. */
        public void dump() {
            if (isEnabled()) 
            {
                Trace.WriteLine(name + ' ' + value);
            }
        }


        /**
        /// Determines if this StatisticsVariable is enabled
         *
        /// @return true if enabled
         */
        public Boolean isEnabled() 
        {
            return enabled;
        }


        /**
        /// Sets the enabled state of this StatisticsVariable
         *
        /// @param enabled the new enabled state
         */
        public void setEnabled(Boolean enabled) 
        {
            this.enabled = enabled;
        }


        /** Some simple tests for the StatisticsVariable */
        public static void main(String[] args) 
        {
            StatisticsVariable loops =
                    StatisticsVariable.getStatisticsVariable("main", "loops");
            StatisticsVariable sum =
                    StatisticsVariable.getStatisticsVariable("main", "sum");

            StatisticsVariable foot =
                    StatisticsVariable.getStatisticsVariable("body", "foot");
            StatisticsVariable leg =
                    StatisticsVariable.getStatisticsVariable("body", "leg");
            StatisticsVariable finger =
                    StatisticsVariable.getStatisticsVariable("body", "finger");

            foot.setValue(2);
            leg.setValue(2);
            finger.setValue(10);

            StatisticsVariable.dumpAll();
            StatisticsVariable.dumpAll();

            for (int i = 0; i < 1000; i++) {
                loops.value++;
                sum.value += i;
            }

            StatisticsVariable.dumpAll();


            StatisticsVariable loopsAlias =
                    StatisticsVariable.getStatisticsVariable("main", "loops");
            StatisticsVariable sumAlias =
                    StatisticsVariable.getStatisticsVariable("main", "sum");

            for (int i = 0; i < 1000; i++) {
                loopsAlias.value++;
                sumAlias.value += i;
            }

            StatisticsVariable.dumpAll();
            StatisticsVariable.resetAll();
            StatisticsVariable.dumpAll();
        }
    }
}
